#include "StdAfx.h"
#include "Utility.h"
#include "BitmapDC.h"

CUtility::CUtility(void)
{
}

CUtility::~CUtility(void)
{
}

int CUtility::ParseToken(LPTSTR pSource, const TCHAR cDelimit, LPTSTR pToken[], int nCount)
{
	LPTSTR pNext = pSource;

	int i;
	for(i = 0; pNext && i < nCount; ++i)
	{
		pToken[i] = pNext;
		pNext = _tcschr(pNext, cDelimit);
		if(pNext)
		{
			*pNext = 0;
			++pNext;
		}
	}

	return i;
}

HRGN CUtility::CreateBitmapRgn(CDC* pDC, CBitmap* pBitmap, COLORREF clrMask)
{
	CBitmapDC BmpDC(pDC, pBitmap);
	BITMAP bmp;
	pBitmap->GetBitmap(&bmp);
	CSize size;
	size.cx = bmp.bmWidth;
	size.cy = bmp.bmHeight;
	
	HRGN hRgn = CreateRectRgn(0, 0, 0, 0);
	BOOL bMask;
	RECT rect;
	HRGN hTempRgn;

	for(int y = 0; y < size.cy; ++y)
	{
		bMask = TRUE;
		rect.top = y;
		rect.bottom = y + 1;
		for(int x = 0; x < size.cx; ++x)
		{
			if(BmpDC.GetPixel(x, y) == clrMask || x == (size.cx - 1))
			{
				if(!bMask)
				{
					rect.right = x;
					bMask = TRUE;

					hTempRgn = CreateRectRgn(rect.left, rect.top, rect.right, rect.bottom);
					CombineRgn(hRgn, hRgn, hTempRgn, RGN_OR);
					DeleteObject(hTempRgn);
				}
			}
			else
			{
				if(bMask)
				{
					rect.left = x;
					bMask = FALSE;
				}
			}
		}
	}


	return hRgn;
}

void CUtility::DrawBitmap(CDC* pDC, int x, int y, int nWidth, int nHeight, CBitmap* pBitmap, 
						  int xSrc, int ySrc, BOOL bTransparent, COLORREF clrMask)
{
	CBitmapDC SrcDC(pDC, pBitmap);

	if(bTransparent)
	{
		pDC->TransparentBlt(x, y, nWidth, nHeight, &SrcDC, xSrc, ySrc, nWidth, nHeight, clrMask);
	}
	else
	{
		pDC->BitBlt(x, y, nWidth, nHeight, &SrcDC, xSrc, ySrc, SRCCOPY);
	}
}

void CUtility::DrawBitmapStretch(CDC* pDC, int x, int y, int nWidth, int nHeight, CBitmap* pBitmap, 
					int xSrc, int ySrc, int nSrcWidth, int nSrcHeight, BOOL bTransparent, COLORREF clrMask)
{
	CBitmapDC SrcDC(pDC, pBitmap);

	if(bTransparent)
	{
		pDC->TransparentBlt(x, y, nWidth, nHeight, &SrcDC, xSrc, ySrc, nSrcWidth, nSrcHeight, clrMask);
	}
	else
	{
		pDC->StretchBlt(x, y, nWidth, nHeight, &SrcDC, xSrc, ySrc, nSrcWidth, nSrcHeight, SRCCOPY);
	}
}

time_t CUtility::DateTimeToTime(const COleDateTime &dtDateTime)
{
	SYSTEMTIME dateTime;
	dtDateTime.GetAsSystemTime(dateTime);

	tm atm;

	atm.tm_sec = dateTime.wSecond;
	atm.tm_min = dateTime.wMinute;
	atm.tm_hour = dateTime.wHour;
	atm.tm_mday = dateTime.wDay;
	atm.tm_mon = dateTime.wMonth - 1;        // tm_mon is 0 based
	atm.tm_year = dateTime.wYear - 1900;     // tm_year is 1900 based
	atm.tm_isdst = -1;

	return _mkgmtime(&atm); 
}

COleDateTime CUtility::TimeToDateTime(time_t timeValue)
{
	const tm& atm = *(gmtime(&timeValue));
	return COleDateTime(atm.tm_year+1900, atm.tm_mon+1, atm.tm_mday, atm.tm_hour, atm.tm_min, atm.tm_sec);
}

COLORREF CUtility::AlphaBlendColor(COLORREF clrDst, COLORREF clrSrc, BYTE alpha)
{
	BYTE red = static_cast<BYTE>(GetRValue(clrSrc)*(alpha/255.0f) + GetRValue(clrDst)*(1.0f-(alpha/255.0f)));
	BYTE green = static_cast<BYTE>(GetGValue(clrSrc)*(alpha/255.0f) + GetGValue(clrDst)*(1.0f-(alpha/255.0f)));
	BYTE blue = static_cast<BYTE>(GetBValue(clrSrc)*(alpha/255.0f) + GetBValue(clrDst)*(1.0f-(alpha/255.0f)));

	return RGB(red, green, blue);
}

void CUtility::StretchBltBitmap(CDC* pDC, const CRect& rect, CBitmap* pBitmap, const CRect& rectBitmap, 
								STRETCH_BLT_MODE StretchMode, BOOL bTransparent, COLORREF clrMask)
{
	int ux, uy;
	int s_mx, d_mx, s_my, d_my;
	int sx, dx, sy, dy;

//	CBitmapDC MemDC(pDC, pBitmap);

	switch(StretchMode)
	{
	case STRETCH_BLT_HORIZONTAL:
		ux = rectBitmap.Width() / 3;
		uy = rectBitmap.Height();
		s_mx = rectBitmap.Width() - 2*ux;
		d_mx = rect.Width() - 2*ux;

		sx = rectBitmap.left;
		sy = rectBitmap.top;
		dx = rect.left;
		dy = rect.top;

		DrawBitmap(pDC, dx, dy, ux, uy, pBitmap, sx, sy, bTransparent, clrMask);
	
		dx += ux;
		sx += ux;

		DrawBitmapStretch(pDC, dx, dy, d_mx, uy, pBitmap, sx, sy, s_mx, uy, bTransparent, clrMask);

		dx += d_mx;
		sx += s_mx;

		DrawBitmap(pDC, dx, dy, ux, uy, pBitmap, sx, sy, bTransparent, clrMask);
		break;

	case STRETCH_BLT_VERTICAL:
		ux = rectBitmap.Width();
		uy = rectBitmap.Height()/3;
		s_my = rectBitmap.Height() - 2*uy;
		d_my = rect.Height() - 2*uy;

		sx = rectBitmap.left;
		sy = rectBitmap.top;
		dx = rect.left;
		dy = rect.top;

		DrawBitmap(pDC, dx, dy, ux, uy, pBitmap, sx, sy, bTransparent, clrMask);

		dy += uy;
		sy += uy;

		DrawBitmapStretch(pDC, dx, dy, ux, d_my, pBitmap, sx, sy, ux, s_my, bTransparent, clrMask);

		dy += d_my;
		sy += s_my;

		DrawBitmap(pDC, dx, dy, ux, uy, pBitmap, sx, sy, bTransparent, clrMask);
		break;
		
	case STRETCH_BLT_BORDER:
	case STRETCH_BLT_FULL:
		ux = rectBitmap.Width()/3;
		uy = rectBitmap.Height()/3;

		s_mx = rectBitmap.Width() - 2*ux;
		d_mx = rect.Width() - 2*ux;
		s_my = rectBitmap.Height() - 2*uy;
		d_my = rect.Height() - 2*uy;

		sx = rectBitmap.left;
		sy = rectBitmap.top;
		dx = rect.left;
		dy = rect.top;

		DrawBitmap(pDC, dx, dy, ux, uy, pBitmap, sx, sy, bTransparent, clrMask);

		dx += ux;
		sx += ux;

		DrawBitmapStretch(pDC, dx, dy, d_mx, uy, pBitmap, sx, sy, s_mx, uy, bTransparent, clrMask);

		dx += d_mx;
		sx += s_mx;

		DrawBitmap(pDC, dx, dy, ux, uy, pBitmap, sx, sy, bTransparent, clrMask);

		////////////////
		
		sx = rectBitmap.left;
		sy += uy;
		dx = rect.left;
		dy += uy;

		DrawBitmapStretch(pDC, dx, dy, ux, d_my, pBitmap, sx, sy, ux, s_my, bTransparent, clrMask);

		dx += ux;
		sx += ux;

		if(StretchMode == STRETCH_BLT_FULL)
		{
			DrawBitmapStretch(pDC, dx, dy, d_mx, d_my, pBitmap, sx, sy, s_mx, s_my, bTransparent, clrMask);
		}

		dx += d_mx;
		sx += s_mx;

		DrawBitmapStretch(pDC, dx, dy, ux, d_my, pBitmap, sx, sy, ux, s_my, bTransparent, clrMask);

		///////////////////

		sx = rectBitmap.left;
		sy += s_my;
		dx = rect.left;
		dy += d_my;

		DrawBitmap(pDC, dx, dy, ux, uy, pBitmap, sx, sy, bTransparent, clrMask);

		dx += ux;
		sx += ux;

		DrawBitmapStretch(pDC, dx, dy, d_mx, uy, pBitmap, sx, sy, s_mx, uy, bTransparent, clrMask);

		dx += d_mx;
		sx += s_mx;

		DrawBitmap(pDC, dx, dy, ux, uy, pBitmap, sx, sy, bTransparent, clrMask);
		break;
	}
	
}

void CUtility::SetRect(LPRECT lpRect, const POINT& point, const SIZE& size)
{
	lpRect->left = point.x;
	lpRect->top = point.y;
	lpRect->right = point.x + size.cx;
	lpRect->bottom = point.y + size.cy;

}

int CUtility::TransformCoordinate(int nDestOrg, int nDestExtent, int nSrcCoord, int nSrcOrg, int nSrcExtent)
{
	float fDestOrg =	static_cast<float>(nDestOrg);
	float fDestExtent = static_cast<float>(nDestExtent);
	float fSrcCoord =	static_cast<float>(nSrcCoord);
	float fSrcOrg =		static_cast<float>(nSrcOrg);
	float fSrcExtent =	static_cast<float>(nSrcExtent);

	int nDestCoord = static_cast<int>(
		fDestOrg + (fSrcCoord - fSrcOrg) * fDestExtent / fSrcExtent + 0.5f);

	return nDestCoord;
}

void CUtility::TransformRect(LPRECT lpDestRect, LPCRECT lpExtentRectDest, LPCRECT lpSrcRect, LPCRECT lpExtentRectSrc)
{
	int nSrcExtentWidth = lpExtentRectSrc->right - lpExtentRectSrc->left;
	int nSrcExtentHeight = lpExtentRectSrc->bottom - lpExtentRectSrc->top;
	int nDestExtentWidth = lpExtentRectDest->right - lpExtentRectDest->left;
	int nDestExtentHeight = lpExtentRectDest->bottom - lpExtentRectDest->top;

	lpDestRect->left = TransformCoordinate(lpExtentRectDest->left, nDestExtentWidth, lpSrcRect->left,
		lpExtentRectSrc->left, nSrcExtentWidth);
	lpDestRect->top = TransformCoordinate(lpExtentRectDest->top, nDestExtentHeight, lpSrcRect->top,
		lpExtentRectSrc->top, nSrcExtentHeight);

	lpDestRect->right = TransformCoordinate(lpExtentRectDest->right, nDestExtentWidth, lpSrcRect->right,
		lpExtentRectSrc->right, nSrcExtentWidth);
	lpDestRect->bottom = TransformCoordinate(lpExtentRectDest->bottom, nDestExtentHeight, lpSrcRect->bottom,
		lpExtentRectSrc->bottom, nSrcExtentHeight);

}

void CUtility::SelComboBoxItemByItemData(CComboBox* pComboBox, DWORD_PTR dwData)
{
	int nCount = pComboBox->GetCount();
	for(int i = 0; i < nCount; ++i)
	{
		if(pComboBox->GetItemData(i) == dwData)
		{
			pComboBox->SetCurSel(i);
			break;
		}
	}
}

int CUtility::MessageBox(UINT nType, LPCTSTR lpszFormat, ...)
{
	va_list args;
	va_start(args, lpszFormat);

	CString strText;
	strText.FormatV(lpszFormat, args);
	va_end(args);

	return AfxMessageBox(strText, nType);
}

void CUtility::ScaleRect(LPRECT lpRect, int nWidth, int nHeight)
{
	float fXScale = 0.0f;
	float fYScale = 0.0f;

	int nOldWidth = lpRect->right - lpRect->left;
	int nOldHeight = lpRect->bottom - lpRect->top;

	if(nOldWidth <= 0 || nOldHeight <= 0)
		return;

	if(nWidth > 0)
	{
		fXScale = static_cast<float>(nWidth)/static_cast<float>(nOldWidth);
		fYScale = fXScale;
	}

	if(nHeight > 0)
	{
		fYScale = static_cast<float>(nHeight)/static_cast<float>(nOldHeight);
		if(fXScale == 0.0f)
			fXScale = fYScale;
	}

	if(fXScale == 0.0f)
		return;

	nWidth = static_cast<int>(fXScale * static_cast<float>(nOldWidth) + 0.5f);
	nHeight = static_cast<int>(fYScale * static_cast<float>(nOldHeight) + 0.5f);
	
	lpRect->right = lpRect->left + nWidth;
	lpRect->bottom = lpRect->top + nHeight;
}

BOOL CUtility::ParseTime(LPCTSTR lpszTime, SYSTEMTIME* lpSysTime)
{
	TCHAR szBuf[20];
	TCHAR* pBuf = szBuf+12;
	_tcscpy(szBuf, lpszTime);

	lpSysTime->wSecond = _ttoi(pBuf);
	*pBuf = 0;

	pBuf -= 2;
	lpSysTime->wMinute = _ttoi(pBuf);
	*pBuf = 0;

	pBuf -= 2;
	lpSysTime->wHour = _ttoi(pBuf);
	*pBuf = 0;

	pBuf -= 2;
	lpSysTime->wDay = _ttoi(pBuf);
	*pBuf = 0;

	pBuf -= 2;
	lpSysTime->wMonth = _ttoi(pBuf);
	*pBuf = 0;

	pBuf -= 4;
	lpSysTime->wYear = _ttoi(pBuf);
	
	lpSysTime->wMilliseconds = 0;

	return TRUE;
}

int CUtility::GetDayNumberOfMonth(int nYear, int nMonth)
{
	int nNextMonth = nMonth % 12 + 1;
	int nNextYear = nYear;

	if(nNextMonth == 1)
		nNextYear = nYear+1;
		
	
	COleDateTime dtFirstDay(nYear, nMonth, 1, 0, 0, 0);
	COleDateTime dtLastDay(nNextYear, nNextMonth, 1, 0, 0, 0);

	COleDateTimeSpan span = dtLastDay - dtFirstDay;

	return span.GetDays();
}

BOOL CUtility::EqualDate(const COleDateTime& dtTime1, const COleDateTime& dtTime2)
{
	SYSTEMTIME st1, st2;
	COleDateTime dtDate1, dtDate2;

	dtTime1.GetAsSystemTime(st1);
	dtTime2.GetAsSystemTime(st2);

	dtDate1.SetDate(st1.wYear, st1.wMonth, st1.wDay);
	dtDate2.SetDate(st2.wYear, st2.wMonth, st2.wDay);

	return (dtDate1 == dtDate2);

}

//class CDCGDIObjectManager

CDCGDIObjectManager::~CDCGDIObjectManager()
{
	if(m_pOldFont)
		m_pDC->SelectObject(m_pOldFont);

	if(m_pOldBitmap)
		m_pDC->SelectObject(m_pOldBitmap);

	if(m_pOldPen)
		m_pDC->SelectObject(m_pOldPen);

	if(m_pOldBrush)
		m_pDC->SelectObject(m_pOldBrush);
}